package com.example.myapplication.utils

import android.util.Log
import com.example.myapplication.App
import com.example.myapplication.DEFAULT_CHUNK_SIZE
import com.example.myapplication.ui.download.FileDownloadBean
import okhttp3.*
import java.io.FileOutputStream
import java.io.IOException
import java.io.RandomAccessFile
/**
 * 文件下载的工具
 */
class FileDownloadUtils {

    interface HttpDownloadListener {

        fun onReady(call: Call, bean: FileDownloadBean)

        fun onFailure(call: Call, bean: FileDownloadBean, e: IOException?)

        fun onResponse(call: Call, response: Response, bean: FileDownloadBean)

        fun onFinish(bean: FileDownloadBean, e: Exception?)

    }


    companion object {

        private fun download(
            call: Call, bean: FileDownloadBean,
            listener: HttpDownloadListener
        ) {
            call.also {
                listener.onReady(it, bean)
            }.enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    listener.onFailure(call, bean, e)
                }

                override fun onResponse(call: Call, response: Response) {
                    val responseBody = response.body()
                    bean.length = responseBody.contentLength() //下载文件的总长度
                    val inp = responseBody.byteStream()
                    val fileOutputStream = FileOutputStream(bean.path)
                    try {
                        val bytes = ByteArray(DEFAULT_CHUNK_SIZE)
                        var len: Int
                        var startTime = System.currentTimeMillis()
                        while (inp.read(bytes).also { len = it } != -1) {
                            val currTime = System.currentTimeMillis()
                            val spaceTime = (currTime - startTime).toDouble() / 1000
                            val downloadByteSize = len / 1024
                            startTime = currTime
                            Log.e("FileDownloadUtils" , " download  spaceTime=$spaceTime downloadByteSize=$downloadByteSize")
                            bean.downloadSpeed = (downloadByteSize / spaceTime).toLong()
                            bean.downloadSize = bean.downloadSize + len
                            fileOutputStream.write(bytes, 0, len)
                            listener.onResponse(
                                call,
                                response,
                                bean
                            )
                        }
                        listener.onFinish(bean, null)
                    } catch (e: Exception) {
                        listener.onFinish(bean, e)
                    } finally {
                        fileOutputStream.close()
                        inp.close()
                    }
                }
            })
        }

        private fun downloadByPoint(
            call: Call, bean: FileDownloadBean,
            listener: HttpDownloadListener
        ) {
            call.also {
                listener.onReady(it, bean)
            }.enqueue(object : Callback {
                //发送请求
                override fun onFailure(call: Call, e: IOException) {
                    listener.onFailure(call, bean, e)
                }

                override fun onResponse(call: Call, response: Response) {
                    val responseBody = response.body()
                    val inputStream = responseBody.byteStream() //得到输入流
                    val randomAccessFile = RandomAccessFile(bean.path, "rw") //得到任意保存文件处理类实例
                    if (bean.length == 0L) {
                        bean.length = responseBody.contentLength() //得到文件的总字节大小
                        randomAccessFile.setLength(bean.length) //预设创建一个总字节的占位文件
                    }
                    if (bean.downloadSize != 0L) {
                        randomAccessFile.seek(bean.downloadSize)
                    }
                    try {
                        val bytes = ByteArray(2048)
                        var len: Int
                        val downloadSize = bean.length / 10
                        var currReadSize = 0
                        var startTime = System.currentTimeMillis()
                        while (inputStream.read(bytes).also { len = it } != -1) {
                            randomAccessFile.write(bytes, 0, len)
                            currReadSize += len
                            if (currReadSize >= downloadSize) {
                                val currTime = System.currentTimeMillis()
                                val spaceTime = (currTime - startTime).toDouble()/1000
                                val downloadByteSize = (currReadSize / 1024)
                                startTime = currTime
                                Log.e("FileDownloadUtils" , " downloadByPoint  spaceTime=$spaceTime downloadByteSize=$downloadByteSize")
                                bean.downloadSpeed = (downloadByteSize / spaceTime).toLong()
                                bean.downloadSize = bean.downloadSize + currReadSize
                                listener.onResponse(
                                    call,
                                    response,
                                    bean
                                )
                                currReadSize = 0
                            }
                        }
                        listener.onFinish(bean.apply {
                            this.downloadSize = randomAccessFile.filePointer
                        }, null)
                    } catch (e: Exception) {
                        listener.onFinish(bean.apply {
                            this.downloadSize = randomAccessFile.filePointer //记录当前保存文件的位置
                        }, e)
                    } finally {
                        randomAccessFile.close()
                        inputStream.close()
                    }
                }
            })
        }

        fun getDownRequest(
            bean: FileDownloadBean,
            listener: HttpDownloadListener
        ) {
            val request: Request = Request.Builder()
                .url(bean.url)
                .get()
                .build()
            val client = App.instance.apiNetwork.client()
            download(client.newCall(request), bean, listener)
        }

        /**
         * 有断点续传功能的get下载
         */
        fun getRenewalDownRequest(
            bean: FileDownloadBean,
            listener: HttpDownloadListener
        ) {
            val request: Request = Request.Builder()
                .url(bean.url)
                .header("RANGE", "bytes=${bean.downloadSize}-")
                .build()
            val client = App.instance.apiNetwork.client()
            downloadByPoint(client.newCall(request), bean, listener)
        }


        fun postDownRequest(
            bean: FileDownloadBean,
            body: RequestBody,
            listener: HttpDownloadListener
        ) {
            val request: Request = Request.Builder()
                .url(bean.url)
                .post(body)
                .build()
            val client = App.instance.apiNetwork.client()
            download(client.newCall(request), bean, listener)
        }

        /**
         * 支持断点续传的post下载
         */
        fun postRenewalDownRequest(
            bean: FileDownloadBean,
            body: RequestBody,
            listener: HttpDownloadListener
        ) {
            val request: Request = Request.Builder()
                .url(bean.url)
                .header("RANGE", "bytes=${bean.downloadSize}-")
                .post(body)
                .build()
            val client = App.instance.apiNetwork.client()
            downloadByPoint(client.newCall(request), bean, listener)
        }
    }
}